// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * Main entry point called once the page has loaded.
 */
function onLoad() {
  NetExportView.getInstance();
}
document.addEventListener('DOMContentLoaded', onLoad);

function $(id) {
  const el = document.getElementById(id);
  return el;
}

/**
 * This class handles the presentation of the net-export view. Used as a
 * singleton.
 */
const NetExportView = (function() {
  'use strict';

  // --------------------------------------------------------------------------

  const kIdStateDivUninitialized = 'state-uninitialized';
  const kIdStateDivInitial = 'state-initial';
  const kIdStateDivLogging = 'state-logging';
  const kIdStateDivStopped = 'state-stopped';
  const kIdStartLoggingButton = 'start-logging';
  const kIdStopLoggingButton = 'stop-logging';
  const kIdShowFileButton = 'show-file';
  const kIdCaptureModeLogging = 'capture-mode-logging';
  const kIdFilePathLogging = 'file-path-logging';
  const kIdCaptureModeStopped = 'capture-mode-stopped';
  const kIdFilePathStoppedLogging = 'file-path-stopped';
  const kIdStartOverButton = 'startover';
  const kIdPrivacyReadMoreLink = 'privacy-read-more-link';
  const kIdPrivacyReadMoreDiv = 'privacy-read-more';
  const kIdTooBigReadMoreLink = 'toobig-read-more-link';
  const kIdTooBigReadMoreDiv = 'toobig-read-more';
  const kIdLogMaxFileSizeInput = 'log-max-filesize';

  /**
   * @constructor
   */
  function NetExportView() {
    // Tell NetExportMessageHandler to notify the UI of future state changes
    // from this point on (through onExportNetLogInfoChanged()).
    chrome.send('enableNotifyUIWithState');

    this.infoForLoggedFile_ = null;
  }

  NetExportView.getInstance = function() {
    return NetExportView.instance_ ||
        (NetExportView.instance_ = new NetExportView());
  };

  NetExportView.prototype = {
    /**
     * Starts saving NetLog data to a file.
     */
    onStartLogging_() {
      // Determine the capture mode to use.
      const logMode =
          document.querySelector('input[name="log-mode"]:checked').value;

      // Determine the maximum file size, as the number of bytes (or -1 to mean
      // no limit)
      let maxLogFileSizeBytes = -1;
      const fileSizeString = $(kIdLogMaxFileSizeInput).value;
      const numMegabytes = parseFloat(fileSizeString);
      if (!isNaN(numMegabytes)) {
        // Convert to an integral number of bytes.
        maxLogFileSizeBytes = Math.round(numMegabytes * 1024 * 1024);
      }

      chrome.send('startNetLog', [logMode, maxLogFileSizeBytes]);
    },

    /**
     * Stops saving NetLog data to a file.
     */
    onStopLogging_() {
      chrome.send('stopNetLog');
    },

    /**
     * Reveals the log file in the shell (i.e. selects it in the Finder on
     * Mac).
     */
    onShowFile_() {
      chrome.send('showFile');
    },

    /**
     * Transitions back to the "Start logging to disk" state.
     */
    onStartOver_() {
      this.infoForLoggedFile_ = null;
      this.renderInitial_();
    },

    /**
     * Updates the UI to reflect the current state. The state transitions are
     * sent by the browser controller (NetLogFileWriter):
     *
     *   * UNINITIALIZED - This is the initial state when net-export is opened
     *         for the first time, or there was an error during initialization.
     *         This state is short-lived and likely not observed; will
     *         immediately transition to INITIALIZING).
     *
     *   * INITIALIZING - On desktop UI this is pretty much a no-op. On the
     *         mobile UI, this state is when the controller checks the disk for
     *         a previous net-log file (from past run of the browser). After
     *         success will transition to NOT_LOGGING. On failure will
     *         transition to UNINITIALIZED (rare).
     *
     *   * NOT_LOGGING - This is the steady-state. It means initialization
     *        completed and we are not currently logging. Being in this state
     *        either means:
     *         (1) We were logging and then the user stopped (earlier states
     *             were STATE_LOGGING / STATE_STOPPING_LOG).
     *         (2) We have never started logging (previous state was
     *             INITIALIZING).
     *
     *   * STARTING_LOG - This state means the user has clicked the "Start log"
     *        button and logging is about to get started (files may not have
     *        been created yet).
     *
     *   * LOGGING - This state means that logging is currently in progress.
     *        The destination path of the log, and the capture mode are known
     *        and will be reflected in the parameters.
     *
     *   * STOPPING_LOG - This state means the user has clicked the "Stop
     *        logging" button, and the log file is in the process of being
     *        finalized. Once the state transitions to NOT_LOGGING then the log
     *        is complete, and can safely be copied/emailed.
     */
    onExportNetLogInfoChanged(info) {
      switch (info.state) {
        case 'UNINITIALIZED':
        case 'INITIALIZING':
          this.renderUninitialized_();
          break;

        case 'NOT_LOGGING':
          if (this.infoForLoggedFile_) {
            // There is no "stopped logging" state. We manufacture that in the
            // UI in response to a transition from LOGGING --> NOT_LOGGING.
            this.renderStoppedLogging_(this.infoForLoggedFile_);

            // TODO(eroman): prevent future state transitions. In desktop UI
            // could start logging in a new tab, and it would reset this one.
          } else if (info.logExists) {
            // In the mobile UI, initialization may have found a
            // pre-existing log file.
            this.renderStoppedLogging_(info);
          } else {
            this.renderInitial_();
          }
          break;

        case 'STARTING_LOG':
          // This is a short-lived state, no need to do anything special.
          // Disabling the buttons would be nice, however it is not crucial as
          // the controller will reject commands while in this state anyway.
          this.renderInitial_();
          break;

        case 'LOGGING':
          // Cache the last information for this logging session, so once
          // logging is stopped will know what path information to display.
          this.infoForLoggedFile_ = info;
          this.renderLogging_(info);
          break;

        case 'STOPPING_LOG':
          // This is a short-lived state, no need to do anything special.
          this.renderLogging_(info);
          break;
      }
    },

    /**
     * Updates the UI to display the "uninitialized" state. This is only
     * visible for a short period of time, or longer if initialization failed
     * (and didn't transition to a different state).
     */
    renderUninitialized_() {
      this.showStateDiv_(kIdStateDivUninitialized);
    },

    /**
     * Updates the UI to display the "initial" state. This is the state when
     * logging has not been started yet, and there are controls to start
     * logging.
     */
    renderInitial_() {
      this.showStateDiv_(kIdStateDivInitial);
      $(kIdStartLoggingButton).onclick = this.onStartLogging_.bind(this);
    },

    /**
     * Updates the UI to display the "logging" state. This is the state while
     * capturing is in progress and being written to disk.
     */
    renderLogging_(info) {
      this.showStateDiv_(kIdStateDivLogging);
      this.setFavicon_(
          'data:image/svg+xml,<svg version="1.1" ' +
          'xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">' +
          '<circle cx="16" cy="16" r="14" fill="red" stroke="black" /></svg>');
      $(kIdStopLoggingButton).onclick = this.onStopLogging_.bind(this);
      $(kIdCaptureModeLogging).textContent = this.getCaptureModeText_(info);
      $(kIdFilePathLogging).textContent = info.file;
    },

    /*
     * Updates the UI to display the state when logging has stopped.
     */
    renderStoppedLogging_(info) {
      this.setFavicon_('data:image/x-icon;base64,');
      this.showStateDiv_(kIdStateDivStopped);

      if ($(kIdShowFileButton)) {
        $(kIdShowFileButton).onclick = this.onShowFile_.bind(this);
      }

      $(kIdStartOverButton).onclick = this.onStartOver_.bind(this);

      $(kIdFilePathStoppedLogging).textContent = info.file;

      $(kIdCaptureModeStopped).textContent = this.getCaptureModeText_(info);

      // Hook up the "read more..." link for privacy information.
      $(kIdPrivacyReadMoreLink).onclick =
          this.showPrivacyReadMore_.bind(this, true);
      this.showPrivacyReadMore_(false);

      // Hook up the "read more..." link for reducing log size information.
      $(kIdTooBigReadMoreLink).onclick =
          this.showTooBigReadMore_.bind(this, true);
      this.showTooBigReadMore_(false);
    },

    /**
     * Gets the textual label for a capture mode from the HTML.
     */
    getCaptureModeText_(info) {
      // TODO(eroman): Should not hardcode "Unknown" (will not work properly if
      //               the HTML is internationalized).
      if (!info.logCaptureModeKnown) {
        return 'Unknown';
      }

      const radioButton = document.querySelector(
          'input[name="log-mode"][value="' + info.captureMode + '"]');
      if (!radioButton) {
        return 'Unknown';
      }
      return radioButton.parentElement.textContent;
    },

    showPrivacyReadMore_(show) {
      $(kIdPrivacyReadMoreDiv).hidden = !show;
      $(kIdPrivacyReadMoreLink).hidden = show;
    },

    showTooBigReadMore_(show) {
      $(kIdTooBigReadMoreDiv).hidden = !show;
      $(kIdTooBigReadMoreLink).hidden = show;
    },

    showStateDiv_(divId) {
      const kAllDivIds = [
        kIdStateDivUninitialized, kIdStateDivInitial, kIdStateDivLogging,
        kIdStateDivStopped
      ];

      for (const curDivId of kAllDivIds) {
        $(curDivId).hidden = divId !== curDivId;
      }
    },

    /**
     * Sets the icon for the tab to reflect current capturing state.
     */
    setFavicon_(dataUrl) {
      document.getElementById('fav-icon').href = dataUrl;
    }
  };

  return NetExportView;
})();
